package MP.syntaxanalysis;

import java.io.*;
import MP.lexicalanalysis.*;
//ThemVao



public class AstPrinter implements Visitor {
  private int indent;


  public AstPrinter() {
    indent = 0;
  }

  private String indentString() {
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i < indent; ++i) {
      sb.append("  ");
    }
    return sb.toString();
  }

  void print(String s) {
    System.out.println(s);
  }
  public final void print(AST ast) {
    ast.visit(this);
  }
  // ProgramAST
  public void visitProgramAST(ProgramAST ast) {
    print(indentString() + "Program(");
    ++indent;
    ast.v.visit(this);
	ast.p.visit(this);
	ast.c.visit(this);
    --indent;
	print(indentString() +")");
	return;
  }

/*   //ConstDeclAST
  public void visitConstDeclAST(ConstDeclAST ast){
		ConstDeclAST cAst = (ConstDeclAST) ast;
		print(indentString() + "ConstDecl(" );
		++indent;
		print(indentString()+ cAst.name.Lexeme);
		cAst.l.visit(this);
		--indent;
		print(indentString()+")");
	  }*/
// VarDeclPartAST
  public void visitVarDeclPartAST(VarDeclPartAST ast) {
	print(indentString() + "VarDeclPart(");
	++indent;
	ast.o.visit(this);
	ast.v.visit(this);
	--indent;
	print(indentString() +")");
	return;	
  }
  //EmptyVarDeclPartAST
  public void visitEmptyVarDeclPartAST(EmptyVarDeclPartAST ast) {
	    return ;
  }
  
  // OneDeclAST
  public void visitVarDeclAST(OneDeclAST ast) {
	VarDeclAST vAst = (VarDeclAST) ast;
	print(indentString() + "VarDecl(");
	++indent;
	print(indentString()+vAst.name.Lexeme);
	vAst.t.visit(this);	
	--indent;
	print(indentString()+")");
  }
  //ConstDeclAST
  public void visitConstDeclAST(OneDeclAST ast){
		ConstDeclAST cAst = (ConstDeclAST) ast;
		print(indentString() + "ConstDecl(" );
		++indent;
		print(indentString()+ cAst.name.Lexeme);
		cAst.l.visit(this);
		--indent;
		print(indentString()+")");
	  }


  
  //ArrayTypeAST
  public void visitArrayTypeAST(ArrayTypeAST ast){
	  ArrayTypeAST aAst=(ArrayTypeAST) ast;
	  print(indentString()+"ArrayType(");
	  ++indent;
	  aAst.type.visit(this);
	  print(indentString()+aAst.lower.Lexeme);
	  print(indentString()+aAst.upper.Lexeme);
	  --indent;
	  print(indentString()+")");
  }

  //EmptyExprListAST
  public void visitEmptyExprListAST(EmptyExprListAST ast){
	  return;
  }
  //ExprListAST
  public void visitExprListAST(ExprListAST ast){
	  ExprListAST eAst = (ExprListAST) ast;
		print(indentString() + "ExprList(" );
		++indent;
		eAst.e.visit(this);
		eAst.l.visit(this);
		--indent;
		print(indentString()+")");
  }
    //ProDeclPartAST
  public void visitProDeclPartAST(ProDeclPartAST ast){
	  ProDeclPartAST pAst = (ProDeclPartAST) ast;
		print(indentString() + "ProDeclPart(" );
		++indent;			
		pAst.o.visit(this);
		pAst.p.visit(this);
		--indent;
		print(indentString()+")");		
  }

  //EmptyProDeclPartAST
  public void visitEmptyProDeclPartAST(EmptyProDeclPartAST ast){
	  return;
  }
  //FuncDeclAST
  public void visitFuncDeclAST (FuncDeclAST  fAst){
		
		print(indentString() + "FuncDecl(" );
		++indent;
		print(indentString()+fAst.name.Lexeme);
		fAst.para.visit(this);
		fAst.v.visit(this);
		fAst.p.visit(this);
		fAst.ret.visit(this);
		fAst.c.visit(this);
		--indent;
		print(indentString()+")");
  }

  //ProcDeclAST
  public void visitProcDeclAST (ProcDeclAST ast){
	  ProcDeclAST pAst = (ProcDeclAST) ast;
		print(indentString() + "ProcDecl(" );
		++indent;		
		print(indentString() + pAst.name.Lexeme );
		pAst.para.visit(this);
		pAst.v.visit(this);	
		pAst.p.visit(this);
		pAst.c.visit(this);
		--indent;
		print(indentString()+")");		
  }
  //ParaListAST 
  public void visitParaListAST (ParaListAST  ast){
	  ParaListAST pAst = (ParaListAST) ast;
		print(indentString() + "ParaList(" );
		++indent;		
		pAst.v.visit(this);
		pAst.p.visit(this);		
		--indent;
		print(indentString()+")");		
  }
  //  EmptyParaListAST
  public void visitEmptyParaListAST(EmptyParaListAST ast){
	  return;
  }

  //BoolTypeAST
  public void visitBoolTypeAST(BoolTypeAST ast){	 
	  print(indentString()+"Boolean");	  
  }
  //IntTypeAST
  public void visitIntTypeAST(IntTypeAST ast){	  
	  print(indentString()+"Int");	
  }

  //RealTypeAST
  public void visitRealTypeAST(RealTypeAST  ast){
	  print(indentString()+"Real");	
  }

  //StmtListAST
  public void visitStmtListAST(StmtListAST sAst){
	    
		print(indentString() + "StmtList(" );
		++indent;			
		sAst.o.visit(this);
		sAst.s.visit(this);
		--indent;
		print(indentString()+")");	
  }
  
  //EmptyStmtListAST
  public void visitEmptyStmtListAST(EmptyStmtListAST ast){
	  return;
  }
  
  //OneStmtAST
  public void visitAssiStmtAST(AssiStmtAST aAst){

	  print(indentString()+"AssiStmt(");
	  ++indent;
	  aAst.l.visit(this);
	  aAst.e.visit(this);
	  --indent;
	  print(indentString()+")");
  }

  //IfThenElseStmtAST
  public void visitIfThenElseStmtAST(IfThenElseStmtAST iAst){

		print(indentString() + "IfThenElseStmt(" );
		++indent;		
		iAst.e.visit(this);
		iAst.s1.visit(this);
		iAst.s2.visit(this);		
		--indent;
		print(indentString()+")");
  }
  //IfThenStmtAST
  public void visitIfThenStmtAST(IfThenStmtAST iAst){

		print(indentString() + "IfThenStmt(" );
		++indent;		
		iAst.e.visit(this);
		iAst.s1.visit(this);				
		--indent;
		print(indentString()+")");		
  }
  //RepeatStmtAST
  public void visitRepeatStmtAST(RepeatStmtAST rAst){

		print(indentString() + "RepeatStmt(" );
		++indent;			
		rAst.s.visit(this);
		rAst.e.visit(this);
		--indent;
		print(indentString()+")");		
  }
  //RetNullStmtAST
  public void visitRetNullStmtAST(RetNullStmtAST ast){
	  print(indentString()+"Return()");	
  }
  //RetStmtAST
  public void visitRetStmtAST(RetStmtAST rAst){
	 
		print(indentString() + "RetStmt(" );
		++indent;			
		rAst.e.visit(this);		
		--indent;
		print(indentString()+")");	
  }
  //CallStmtAST
  public void visitCallStmtAST(CallStmtAST ast){
	  
	  print(indentString()+"CallStmt(");
	  ++indent;
	  print(indentString()+ast.name.Lexeme);
	  ast.e.visit(this);
	  --indent;
	  print(indentString()+")");
  }
  //ForStmtAST
  public void visitForStmtAST(ForStmtAST fAst){

		print(indentString() + "ForStmt(" );
		++indent;
		print(indentString()+fAst.name.Lexeme);
		fAst.e1.visit(this);
		if(fAst.to) print(indentString() +"To"); else print(indentString() +"DownTo");
		fAst.e2.visit(this);
		fAst.o.visit(this);
		--indent;
		print(indentString()+")");
  }
  //WhileStmtAST
  public void visitWhileStmtAST(WhileStmtAST wAst){
	    
		print(indentString() + "WhileStmt(" );
		++indent;			
		wAst.e.visit(this);
		wAst.o.visit(this);
		--indent;
		print(indentString()+")");	
  }  
  //BreakStmtAST
  public void visitBreakStmtAST(BreakStmtAST ast){
	  print(indentString()+"Break()");	  
  }
  //CompStatAST
  public void visitCompStatAST(CompStatAST cAst){

	  print(indentString()+"CompStmt(");
	  ++indent;
	  cAst.v.visit(this);
	  cAst.s.visit(this);
	  --indent;
	  print(indentString()+")");
  }
  //ContStmtAST
  public void visitContStmtAST(ContStmtAST ast){
	  print(indentString()+"Continue()");	  
  }

  public void visitLvalueAST(LvalueAST ast) {
		print(indentString() + "Lvalue(" );
		++indent;			
		print(indentString() + ast.name.Lexeme);
		if (!(ast.e instanceof EmptyExprListAST)) ast.e.visit(this);
		--indent;
		print(indentString()+")");
	}
    //LiteralAST
  public void visitIntLiteralAST(IntLiteralAST  ast){
	  
		print(indentString() + "IntLiteral(" );
		++indent;		
		print(indentString() + ast.literal.Lexeme );		
		--indent;
		print(indentString()+")");		
  }
  public void visitRealLiteralAST(RealLiteralAST  ast){
	  
		print(indentString() + "RealLiteral(" );
		++indent;		
		print(indentString() + ast.literal.Lexeme );		
		--indent;
		print(indentString()+")");		
  } 
  public void visitBoolLiteralAST(BoolLiteralAST  ast){
	  
		print(indentString() + "BoolLiteral(" );
		++indent;		
		print(indentString() + ast.literal.Lexeme );		
		--indent;
		print(indentString()+")");		
  }  
  public void visitStringLiteralAST(StringLiteralAST  ast){
	  
		print(indentString() + "StringLiteral(" );
		++indent;		
		print(indentString() + ast.literal.Lexeme );		
		--indent;
		print(indentString()+")");		
  }
  //UnaryExprAST
  public void visitUnaryExprAST(UnaryExprAST ast){
	  UnaryExprAST uAst = (UnaryExprAST) ast;
		print(indentString() + "UnaryExpr(" );
		++indent;			
		print(indentString() + uAst.op.Lexeme );
		uAst.e.visit(this);
		--indent;
		print(indentString()+")");	
  }
  //BinExprAST
  public void visitBinExprAST(BinExprAST ast){
	  BinExprAST bAst=(BinExprAST) ast;
	  print(indentString()+"BinExpr(");
	  ++indent;
	  bAst.e1.visit(this);
	  print(indentString()+bAst.op.Lexeme);
	  bAst.e2.visit(this);
	  --indent;
	  print(indentString()+")");
  }
  //VarExprAST
  public void visitVarExprAST(VarExprAST ast){
	  VarExprAST vAst = (VarExprAST) ast;
		print(indentString() + "VarExpr(" );
		++indent;			
		print(indentString() + vAst.name.Lexeme );		
		--indent;
		print(indentString()+")");	
  }
  //EleExprAST
  public void visitEleExprAST(EleExprAST ast){
	  EleExprAST eAst = (EleExprAST) ast;
		print(indentString() + "EleExpr(" );
		++indent;
		print(indentString()+ eAst.name.Lexeme);
		eAst.e.visit(this);
		--indent;
		print(indentString()+")");
  }  
  //CallExprAST
  public void visitCallExprAST(CallExprAST ast){
	  CallExprAST cAst=(CallExprAST) ast;
	  print(indentString()+"CallExpr(");
	  ++indent;
	  print(indentString()+cAst.name.Lexeme);
	  cAst.e.visit(this);
	  --indent;
	  print(indentString()+")");
  }
}


